﻿using System;
using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;
using System.Linq;

namespace TaskParallelLibrary
{
    class Program
    {
        const string blog = "http://andrea-angella.blogspot.co.uk/";

        static void Main()
        {
            //LearnTasks();

            Stopwatch timer;
            timer = Stopwatch.StartNew();
            LearnParallelFor();
            Console.WriteLine("Time: {0} sec", timer.Elapsed.TotalSeconds);

//            timer = Stopwatch.StartNew();
//            NormalFor();
//            Console.WriteLine("Time: {0} sec", timer.Elapsed.TotalSeconds);

            timer = Stopwatch.StartNew();
            LearnParallelForeach();
            Console.WriteLine("Time: {0} sec", timer.Elapsed.TotalSeconds);

            Console.WriteLine("END");
            Console.ReadKey();
        }

        private static void LearnParallelForeach()
        {
            bool[] completed = new bool[100];

            Parallel.ForEach(Enumerable.Range(0, 100), i =>
            {
                try
                {
                    Calculate(blog);
                    completed[i] = true;
                    Console.WriteLine("{0} completed.", i);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("{0} failed: {1}", i, ex.Message);
                }
            });

            Console.WriteLine("Total complete tasks {0}", completed.Count(x => x));            
        }

        private static void NormalFor()
        {
            bool[] completed = new bool[100];

            for (int i=0; i< 100; ++i)
            {
                try
                {
                    Calculate(blog);
                    completed[i] = true;
                    Console.WriteLine("{0} completed.", i);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("{0} failed: {1}", i, ex.Message);
                }
            }

            Console.WriteLine("Total complete tasks {0}", completed.Count(x => x));
        }

        private static void LearnParallelFor()
        {
            bool[] completed = new bool[100];

            try
            {
                Parallel.For(0, 100, i =>
                    {
                        try
                        {
                            Calculate(blog);
                            completed[i] = true;
                            Console.WriteLine("{0} completed.", i);
                        }
                        catch(Exception ex)
                        {
                            Console.WriteLine("{0} failed: {1}", i, ex.Message);                            
                        }
                    });
            }
            catch (AggregateException ex)
            {
                foreach (var innerException in ex.InnerExceptions)
                {
                    Console.WriteLine(innerException);
                }
            }

            Console.WriteLine("Total complete tasks {0}", completed.Count(x => x));
        }

        private static void LearnTasks()
        {
            Task task = Task.Run(() => Calculate(blog))
                            .ContinueWith(t =>
                                {
                                    var page = t.Result;

                                    Console.Write(page);
                                });

            Console.WriteLine("Id: " + task.Id);
            Console.WriteLine("IsCompleted: " + task.IsCompleted);
            Console.WriteLine("IsCanceled: " + task.IsCanceled);
            Console.WriteLine("IsFaulted: " + task.IsFaulted);
            Console.WriteLine("Status: " + task.Status);
            Console.WriteLine("Waiting...");

            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex.Message);

                foreach (var innerException in ex.InnerExceptions)
                {
                    Console.WriteLine(innerException);
                }
            }
        }

        private static string Calculate(string uri)
        {
            var webClient = new WebClient();
            string page = webClient.DownloadString(new Uri(uri));

            return page;
        }
    }
}
